/**
 * Copyright (c) 2005-2011 springside.org.cn
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * <p>
 * $Id: EncodeUtils.java 1595 2011-05-11 16:41:16Z calvinxiu $
 */
package com.gomcarter.frameworks.base.common;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * 封装各种格式的编码解码工具类.
 * <p>
 * 1.Commons-Codec的hex/base64 编码
 * 2.Commons-Lang的xml/html escape
 * 3.JDK提供的URLEncoder
 *
 * @author gomcarter
 */
public final class EncodeUtils {
    private static final String ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    private static final String DEFAULT_URL_ENCODING = "UTF-8";

    /**
     * Hex编码, byte[]-&gt;String.
     *
     * @param input 需要编码的 byte
     * @return 编码结果
     */
    public static String encodeHex(byte[] input) {
        return Hex.encodeHexString(input);
    }

    /**
     * Hex解码, String-&gt;byte[].
     *
     * @param input 需要解码的字符串
     * @return 解码结果
     * @throws DecoderException for DecoderException
     */
    public static byte[] decodeHex(String input) throws DecoderException {
        return Hex.decodeHex(input.toCharArray());
    }

    /**
     * Base64编码, byte[]-&gt;String.
     *
     * @param input 需要编码的 byte
     * @return 编码结果
     */
    public static String encodeBase64(byte[] input) {
        return Base64.encodeBase64String(input);
    }

    /**
     * Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548).
     *
     * @param input 需要编码的字符串
     * @return 编码结果
     */
    public static String encodeUrlSafeBase64(byte[] input) {
        return Base64.encodeBase64URLSafeString(input);
    }

    /**
     * Base64解码, String-&gt;byte[].
     *
     * @param input 需要解码的字符串
     * @return 解码结果
     */
    public static byte[] decodeBase64(String input) {
        return Base64.decodeBase64(input);
    }

    /**
     * Base62(0_9A_Za_z)编码数字, long-&gt;String.
     *
     * @param num 需要编码的字符串
     * @return 编码结果
     */
    public static String encodeBase62(long num) {
        return alphabetEncode(num, 62);
    }

    /**
     * Base62(0_9A_Za_z)解码数字, String -&gt; long.
     *
     * @param str 需要解码的字符串
     * @return 解码结果
     */
    public static long decodeBase62(String str) {
        return alphabetDecode(str, 62);
    }

    private static String alphabetEncode(long num, int base) {
        num = Math.abs(num);
        StringBuilder sb = new StringBuilder();
        for (; num > 0; num /= base) {
            sb.append(ALPHABET.charAt((int) (num % base)));
        }

        return sb.toString();
    }

    private static long alphabetDecode(String str, int base) {
        AssertUtils.notNull(str);

        long result = 0;
        for (int i = 0; i < str.length(); i++) {
            result += ALPHABET.indexOf(str.charAt(i)) * Math.pow(base, i);
        }

        return result;
    }

    /**
     * URL 编码, Encode默认为UTF-8.
     *
     * @param part for input
     * @return 编码结果
     * @throws UnsupportedEncodingException for exception
     */
    public static String urlEncode(String part) throws UnsupportedEncodingException {
        return URLEncoder.encode(part, DEFAULT_URL_ENCODING);
    }

    /**
     * URL 解码, Encode默认为UTF-8.
     *
     * @param part for input
     * @return 解码结果
     * @throws UnsupportedEncodingException for exception
     */
    public static String urlDecode(String part) throws UnsupportedEncodingException {
        return URLDecoder.decode(part, DEFAULT_URL_ENCODING);
    }

}
